package star.cloud.asme.base.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import star.cloud.asme.system.user.User;
import star.cloud.asme.system.user.UserMapper;

import java.util.HashMap;
import java.util.Map;

@Configuration
@Slf4j
@RequiredArgsConstructor
public class SpringSecurityBeans {
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private final UserMapper userMapper;

    @Bean
    public PasswordEncoder passwordEncoder() {
        String idForEncode = "bcrypt";
        Map<String, PasswordEncoder> encoders = new HashMap<>();
        encoders.put(idForEncode, new BCryptPasswordEncoder());
        return new DelegatingPasswordEncoder(idForEncode, encoders);
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> {
            log.info("userDetailsService is running with {}", username);
            User user = userMapper.selectOneByUsername(username);
            if (user == null) {
                log.info("用户名不存在。");
                throw new UsernameNotFoundException("用户名不存在。");
            } else {
                return User.builder().username(username).password(user.getPassword()).build();
            }

        };
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        authenticationProvider.setUserDetailsService(userDetailsService());
        authenticationProvider.setUserDetailsPasswordService(userDetailsPasswordService());
        return authenticationProvider;
    }

    @Bean
    public UserDetailsPasswordService userDetailsPasswordService() {
        return (user, newPassword) -> null;
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            log.info("accessDeniedHandler with {}", request.getRequestURI());
            response.setContentType(SpringSecurityConstant.APPLICATION_JSON_CHARSET_UTF_8);
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.getWriter().println(OBJECT_MAPPER.writeValueAsString("访问未授权。"));
        };
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            log.info("authenticationEntryPoint with {}", request.getRequestURI());
            response.setContentType(SpringSecurityConstant.APPLICATION_JSON_CHARSET_UTF_8);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.getWriter().write("登录失败。");
        };
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(authenticationProvider());
    }


}